﻿using System;
using System.Collections.Generic;
using System.IO;

namespace MTP
{
    public class MTPPackage : IDisposable
    {
        internal static MTPPackage BuilderErrorPackage(Exception throwable)
        {
            var buffer = Buffer.ByteWriteBuffer.Alloc()
                .Write(throwable.HResult)
                .WriteUnknownString(throwable.Message);

            return new MTPPackage(buffer.ToBytes(), PackageType.Error, null);
        }

        public static MTPPackage Builder(string value, IDictionary<string, string> header = null)
        {
            return new MTPPackage(System.Text.Encoding.UTF8.GetBytes(value), PackageType.String, header);
        }

        public static MTPPackage Builder(byte[] bytes, IDictionary<string, string> header = null)
        {
            return new MTPPackage(bytes, PackageType.ByteArray, header);
        }

        public static MTPPackage Builder(Stream stream, IDictionary<string, string> header = null)
        {
            return new MTPPackage(stream, PackageType.Stream, header);
        }
        internal MTPPackage(byte[] bytes, PackageType packageType, IDictionary<string, string> header) :
            this(new MemoryStream(bytes), packageType, header)
        {

        }
        internal MTPPackage(Stream stream, PackageType packageType, IDictionary<string, string> header)
        {
            this.Stream = stream;
            this.PackageType = packageType;
            this.Header = header;
        }

        public IDictionary<string, string> Header { get; }

        public PackageType PackageType { get; }

        public Stream Stream { get; }

        public byte[] GetByteArray()
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                Stream.CopyTo(memoryStream);
                return memoryStream.ToArray();
            }
        }

        public string GetString()
        {
            return System.Text.Encoding.UTF8.GetString(GetByteArray());
        }

        public void Dispose()
        {
            Stream.Dispose();
        }
        public MTPPackage TryThrowException()
        {
            if (PackageType != PackageType.Error)
            {
                return this;
            }
            var buffer = Buffer.ByteReadBuffer.Wrap(GetByteArray());
            int code = buffer.ReadInt();
            string message = buffer.ReadUnknownString();
            throw new DispatchException(message, code);
        }
    }
}
